#include "ImageHandle.h"
#include "base64.h"
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>

using namespace cv;

cv::Mat ImageHandle::Binarization(cv::Mat img, int thresh, int maxval)
{
  cv::Mat output;
  cv::Mat grayImg;

  if (img.channels() == 1)
  {
    grayImg = img;
  }
  else if (img.channels() == 3)
  {
    cv::cvtColor(img, grayImg, cv::COLOR_BGR2GRAY);
  }
  else
  {
    // 处理其他通道数的图像
    std::cerr << "Error: Unsupported number of channels." << std::endl;
  }

  cv::threshold(grayImg, output, thresh, maxval, cv::THRESH_BINARY);
  return output;
}

// alpha 是亮度增益系数，控制亮度的放大或缩小程度，而 beta
// 是亮度偏移量，控制亮度的整体增加或减少
cv::Mat ImageHandle::BrightnessEnforce(cv::Mat image, double alpha,
                                       double beta)
{
  cv::Mat new_image = cv::Mat::zeros(image.size(), image.type());
  for (int y = 0; y < image.rows; y++)
  {
    for (int x = 0; x < image.cols; x++)
    {
      new_image.at<uchar>(y, x) = cv::saturate_cast<uchar>(
          alpha * (image.at<uchar>(y, x)) +
          beta); // 亮度调整公式 new_pixel = alpha * old_pixel + beta
    }
  }
  return new_image;
}

cv::Mat ImageHandle::Color2Gray(cv::Mat img)
{
  if (!img.empty() && img.channels() == 3)
  {
    try
    {
      cv::cvtColor(img, img, cv::COLOR_BGR2GRAY);
    }
    catch (const cv::Exception &e)
    {
      std::cerr << e.what() << std::endl;
    }
  }

  return img;
}

DetectionResult ImageHandle::CircleRecognition(cv::Mat &img_raw,
                                               cv::Rect &roiRect,
                                               cv::Mat &img,
                                               std::vector<cv::Vec3f> &circles,
                                               int minDst, int threshold1,
                                               int threshold2, int minRadius,
                                               int maxRadius)
{
  DetectionResult result;

  // 灰度处理
  cv::Mat grayImage = this->Color2Gray(img);

  // 高斯滤波
  cv::Mat blurred;
  GaussianBlur(grayImage, blurred, Size(9, 9), 2, 2);

  // 圆形检测
  HoughCircles(blurred, circles, cv::HOUGH_GRADIENT, 1, minDst, threshold1,
               threshold2, minRadius, maxRadius);
  result.num_points = circles.size();
  int num = 0;

  std::vector<cv::Point2f> coordinates;
  for (size_t i = 0; i < circles.size(); i++)
  {
    num++;
    cv::Vec3i c = circles[i];
    cv::Point center = cv::Point(cvRound(c[0]), cvRound(c[1]));
    int radius = cvRound(c[2]);
    cv::circle(img_raw, roiRect.tl() + center, radius, Scalar(0, 0, 255), 10, LINE_AA);

    cv::Scalar textColor(0, 0, 255);
    int fontFace = cv::FONT_HERSHEY_SIMPLEX;
    double fontScale = 2;
    int thickness = 1;
    std::string outputString = "" + std::to_string(i + 1);
    cv::putText(img_raw, outputString, roiRect.tl() + center, fontFace, fontScale,
                textColor, thickness); // sign

    coordinates.push_back(roiRect.tl() + center);
  }

  result.coordinates = coordinates;
  result.img = img_raw;

  return result;
}

std::string ImageHandle::Image2json(cv::Mat image)
{
  char *pOut = ImageBase64Encode(
      image); // 将相机拍摄到的图像进行base64编码，并返回数据指针
  // 构造json
  Json::Value root;        // 一个json数据类
  Json::FastWriter writer; // 一个json写入类
  // 构造json，写入键值
  root["Data"] = pOut;
  // 将json数据转为字符串,json对象序列化
  std::string JsonString;
  JsonString = writer.write(root);
  // 释放资源
  delete[] pOut;
  pOut = NULL;
  return JsonString;
}

char *ImageHandle::ImageBase64Encode(cv::Mat image)
{

  // 将图像编码为内存中的 JPEG 格式
  std::vector<uchar> buffer;
  cv::imencode(".jpg", image, buffer);

  // 将图像数据转换为 Base64 字符串
  int base64_len = calc_base64_len(buffer.size());
  char *pOut = new char[base64_len + 1];
  base64_encode(reinterpret_cast<const char *>(buffer.data()), buffer.size(),
                pOut);
  pOut[base64_len] = 0;

  return pOut;
}

DetectionResult ImageHandle::RectangleRecognition(cv::Mat img,
                                                  int threshold1,
                                                  int threshold2,
                                                  int minArea,
                                                  int maxArea)
{
  DetectionResult result;

  cv::Mat Binarization_img = Binarization(Color2Gray(img),
                                          getBinarParam("ThresholdValue1"),
                                          getBinarParam("ThresholdValue2"));

  // 轮廓检测
  std::vector<std::vector<cv::Point>> contours;
  cv::findContours(Binarization_img, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);

  int num = 0;
  std::vector<Pixel> pixels;
  int centerX, centerY;

  std::vector<cv::Point2f> coordinates;

  // 绘制矩形框,输出并绘制矩形中心点坐标
  for (size_t t = 0; t < contours.size(); t++)
  {
    // 矩形面积判定
    float area = cv::contourArea(contours[t]);
    if (area < minArea * minArea)
      continue;
    if (maxArea != 0)
    {
      if (area >= maxArea * maxArea)
        continue;
    }
    // 使用approxPolyDP近似多边形
    double epsilon = 0.02 * arcLength(contours[t], true);
    std::vector<cv::Point> approx;
    approxPolyDP(contours[t], approx, epsilon, true);
    if (approx.size() != 4)
    {
      continue;
    }
    num++;
    // 找到RotatedRect类型的旋转矩形信息，即矩形四角点位置。
    cv::RotatedRect rect = cv::minAreaRect(contours[t]);
    cv::Point2f vertices[4];
    rect.points(vertices);
    // 描边
    for (int i = 0; i < 4; i++)
    {
      cv::line(img, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 255, 0), 6);
    }
    // 绘制矩形中心点
    cv::Rect rect2 = cv::boundingRect(contours[t]);
    cv::Point center(rect2.x + rect2.width / 2, rect2.y + rect2.height / 2);

    cv::Scalar textColor(0, 0, 255);
    int fontFace = cv::FONT_HERSHEY_SIMPLEX;
    double fontScale = 0.5;
    int thickness = 1;
    std::string outputString = "" + std::to_string(num);
    std::string outputString1 = "" + std::to_string(0);
    cv::putText(img, outputString, cv::Point(centerX, centerY), fontFace,
                fontScale, textColor, thickness); // sign

    coordinates.push_back(cv::Point2f(center.x, center.y));
  }
  result.coordinates = coordinates;
  result.img = img;
  return result;
}

// TemplateMatchParam ImageHandle::PatternRecognition(cv::Mat inputImg,
//                                                    const cv::Mat &inputTempl,
//                                                    int rectangleColor,
//                                                    int rectangleThickness)
// {

//   TemplateMatchParam result;
//   std::vector<cv::Point2f> coordinates;

//   // 参数检查
//   if (inputImg.empty() || inputTempl.empty())
//   {
//     std::cerr << "Error: Input image or template is empty." << std::endl;
//     return result;
//   }

//   // 使用局部变量进行灰度化，避免修改输入参数
//   cv::Mat img, templ;
//   if (inputImg.channels() == 1)
//   {
//     img = inputImg;
//   }
//   else if (inputImg.channels() == 3)
//   {
//     cv::cvtColor(inputImg, img, cv::COLOR_BGR2GRAY);
//   }
//   else
//   {
//     // 处理其他通道数的图像
//     std::cerr << "Error: inputImg Unsupported number of channels." << std::endl;
//   }

//   if (inputTempl.channels() == 1)
//   {
//     templ = inputTempl;
//   }
//   else if (inputTempl.channels() == 3)
//   {
//     cv::cvtColor(inputTempl, templ, cv::COLOR_BGR2GRAY);
//   }
//   else
//   {
//     // 处理其他通道数的图像
//     std::cerr << "Error: inputTempl Unsupported number of channels."
//               << std::endl;
//   }

//   // 初始化SIFT检测器
//   cv::Ptr<cv::xfeatures2d::SIFT> sift = cv::xfeatures2d::SIFT::create(0, 3, 0.04, 10, 1.0);

//   // 找到关键点和描述符
//   std::vector<cv::KeyPoint> kp1, kp2;
//   cv::Mat des1, des2;
//   // sift->detectAndCompute(img, noArray(), kp1, des1);
//   // sift->detectAndCompute(templ, noArray(), kp2, des2);
//   // std::cout << "kp2:  " << kp2.size() << std::endl;

//   cv::Ptr<cv::xfeatures2d::SURF> surf = cv::xfeatures2d::SURF::create();
//   surf->detectAndCompute(img, cv::noArray(), kp1, des1);
//   surf->detectAndCompute(templ, cv::noArray(), kp2, des2);
//   std::cout << "kp2:  " << kp2.size() << std::endl;

//   // 使用FLANN匹配器
//   cv::FlannBasedMatcher matcher;
//   std::vector<std::vector<cv::DMatch>> matches;
//   matcher.knnMatch(des1, des2, matches, 2);

//   std::cout << "Knn success!  " << std::endl;

//   // 筛选好的匹配点
//   std::vector<cv::DMatch> good_matches;
//   for (int i = 0; i < matches.size(); ++i)
//   {
//     if (matches[i][0].distance < 0.7 * matches[i][1].distance)
//     {
//       good_matches.push_back(matches[i][0]);
//     }
//   }

//   std::cout << "good_matches:  " << good_matches.size() << std::endl;

//   // 绘制匹配结果
//   cv::Mat img_matches;
//   drawMatches(inputImg, kp1, inputTempl, kp2, good_matches, img_matches, Scalar::all(-1),
//               Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

//   cv::imwrite("/mnt/e/My_Study/OpenCV/Work_Codes/images/result.jpg", img_matches);

//   // 使用DBSCAN聚类算法对匹配点进行聚类
//   if (!good_matches.empty())
//   {
//     std::vector<cv::Point2f> points1, points2;
//     for (auto &match : good_matches)
//     {
//       points1.push_back(kp1[match.queryIdx].pt);
//       points2.push_back(kp2[match.trainIdx].pt);
//     }

//     cv::Mat mask;
//     std::vector<int> labels;
//     int num_clusters = partition(points1, labels, [&](const cv::Point2f &a, const cv::Point2f &b)
//                                  {
//                                    return norm(a - b) < (inputTempl.cols + inputTempl.rows) / 4; // 设置阈值
//                                  });

//     std::cout << "num_clusters: " << num_clusters << std::endl;

//     // 绘制匹配结果
//     cv::Mat img_matches;
//     cv::drawMatches(inputImg, kp1, inputTempl, kp2, good_matches, img_matches, cv::Scalar::all(-1),
//                     cv::Scalar::all(-1), std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

//     // 绘制聚类簇和中心点
//     for (int i = 0; i < num_clusters; ++i)
//     {
//       std::vector<cv::Point2f> cluster_points1, cluster_points2;
//       for (int j = 0; j < good_matches.size(); ++j)
//       {
//         if (labels[j] == i)
//         {
//           cluster_points1.push_back(points1[j]);
//           cluster_points2.push_back(points2[j]);
//         }
//       }
//       if (cluster_points1.size() < 4)
//       {
//         continue;
//       }

//       // 绘制模板的位置
//       cv::Mat H = cv::findHomography(cluster_points2, cluster_points1, RANSAC);
//       std::cout << "H:  " << H.size() << std::endl;
//       if (H.size() == cv::Size(0, 0))
//       {
//         continue;
//       }
//       std::vector<cv::Point2f> template_corners(4), transformed_corners(4);
//       template_corners[0] = cv::Point2f(0, 0);
//       template_corners[1] = cv::Point2f(0, inputTempl.rows);
//       template_corners[2] = cv::Point2f(inputTempl.cols, inputTempl.rows);
//       template_corners[3] = cv::Point2f(inputTempl.cols, 0);
//       perspectiveTransform(template_corners, transformed_corners, H);
//       for (int j = 0; j < 4; ++j)
//       {
//         line(img_matches, transformed_corners[j], transformed_corners[(j + 1) % 4], cv::Scalar(0, 255, 0), 2);
//       }

//       cv::Point2f center(0, 0);
//       for (int j = 0; j < 4; ++j)
//       {
//         center.x += transformed_corners[j].x;
//         center.y += transformed_corners[j].y;
//       }
//       center.x /= 4;
//       center.y /= 4;

//       // 绘制中心点
//       cv::circle(img_matches, center, 5, Scalar(0, 0, 255), -1);

//       coordinates.push_back(center);
//     }
//     cv::imwrite("/mnt/e/My_Study/OpenCV/Work_Codes/images/result_resulet.jpg", img_matches);

//     result.img = img_matches;
//     result.coordinates = coordinates;
//   }
//   else
//   {
//     std::cout << "No good matches found." << std::endl;
//   }

//   return result;
// }

DetectionResult ImageHandle::PatternRecognition(cv::Mat inputImg,
                                                const cv::Mat &inputTempl,
                                                int rectangleColor,
                                                int rectangleThickness)
{

  DetectionResult result;
  std::vector<cv::Point2f> coordinates;

  // 参数检查
  if (inputImg.empty() || inputTempl.empty())
  {
    std::cerr << "Error: Input image or template is empty." << std::endl;
    return result;
  }

  // 使用局部变量进行灰度化，避免修改输入参数
  cv::Mat img, templ;
  img = Color2Gray(inputImg);
  templ = Color2Gray(inputTempl);

  // 提取轮廓
  std::vector<std::vector<cv::Point>> contours;
  cv::findContours(templ, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

  // 参数检查，确保至少找到一个轮廓
  if (contours.empty())
  {
    std::cerr << "Error: No contour found in the template." << std::endl;
    return result;
  }

  // 提取目标轮廓
  std::vector<cv::Point> contour = contours[0];

  // 进行模板匹配
  cv::Mat templateimg;
  cv::matchTemplate(img, templ, templateimg, cv::TM_CCOEFF_NORMED);

  // 寻找最佳匹配位置
  cv::Point maxLoc;
  cv::minMaxLoc(templateimg, NULL, NULL, NULL, &maxLoc);

  // 显示结果
  cv::rectangle(inputImg, maxLoc,
                cv::Point(maxLoc.x + templ.cols, maxLoc.y + templ.rows),
                cv::Scalar(0, 0, rectangleColor), rectangleThickness);

  coordinates.push_back(cv::Point2f(maxLoc.x + templ.cols / 2, maxLoc.y + templ.rows / 2));

  result.img = inputImg;
  result.coordinates = coordinates;

  return result;
}
